View Javadoc

1   package uba.db;
2   
3   import java.util.ArrayList;
4   import java.util.Collection;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.List;
8   import java.util.Map;
9   
10  import uba.db.column.CharColumnSpecification;
11  import uba.db.column.Column;
12  import uba.db.column.IntegerColumnSpecification;
13  import uba.db.impl.memory.MemoryTable;
14  import uba.db.table.InsertException;
15  import uba.db.table.Row;
16  import uba.db.table.Table;
17  import uba.db.table.TableSchema;
18  import uba.db.table.io.TableReader;
19  
20  /***
21   * Clase base utilizada para simplificar la creación de clases que implementen
22   * {@link uba.db.Database}. 
23   * 
24   * @version $Revision: 1.5 $
25   */
26  public abstract class DatabaseBehavior implements Database {
27      private Map systemTables;
28      private Map userTables;
29      private Map dataTypeIdMap;
30      private Table tablesTable;
31      private Table columnsTable;
32      private Table dataTypesTable;
33  
34      /***
35       * Este método es equivalente a: DatabaseBehavior(null)
36       * 
37       * @see #DatabaseBehavior(Object)
38       */
39      public DatabaseBehavior() throws DatabaseInitializationException {
40          this(null);
41      }
42  
43      /***
44       * Las subclases deben invocar este constructor si desean inicializar la
45       * instancia de la base de datos usando una configuración particular.
46       * 
47       * @param configuration
48       *            "configuración" a utilizar, cada sub-clase debe hacer un cast
49       *            de este objeto según sea necesario.
50       * 
51       * @throws DatabaseInitializationException
52       *             si no se pudo inicializar la base de datos.
53       */
54      public DatabaseBehavior(Object configuration) throws DatabaseInitializationException {
55          configureDatabaseUsing(configuration);
56          initializeSystemTables();
57          initializeSystemTablesMap();
58          initializeDataTypeIdMap();
59          initializeUserTablesMap();
60          initializeUserTables();
61      }
62  
63      private void initializeUserTablesMap() {
64          userTables = new HashMap();
65      }
66  
67      /***
68       * Las sub-clases pueden sobre escribir este método si desean inicializar las
69       * @throws DatabaseInitializationException
70       */
71      protected void initializeUserTables() throws DatabaseInitializationException {}
72  
73      /***
74       * Las sub-clases pueden sobre-escribir este método para configurar la
75       * instancia antes de inicializar la base de datos.
76       * 
77       * @param configuration
78       *            "configuración" a utilizar, cada sub-clase debe hacer un cast
79       *            de este objeto según sea necesario.
80       * 
81       * 
82       * @throws DatabaseInitializationException
83       *             si no se pudo inicializar la base de datos.
84       * 
85       * @see #createTablesTable
86       * @see #createColumnsTable
87       * @see #createDataTypesTable
88       */
89      protected void configureDatabaseUsing(Object configuration)
90              throws DatabaseInitializationException {}
91  
92      private void initializeSystemTables() throws DatabaseInitializationException {
93          try {
94              tablesTable = createTablesTable();
95              columnsTable = createColumnsTable();
96              dataTypesTable = createDataTypesTable();
97          } catch (Exception e) {
98              throw new DatabaseInitializationException(e);
99          }
100     }
101 
102     /***
103      * @see uba.db.Database#tableNamed(java.lang.String)
104      */
105     public Table tableNamed(String tableName) throws UnknowTableName {
106         Table table = basicTableNamed(tableName.toLowerCase());
107 
108         if (table == null) {
109             throw new UnknowTableName(this, tableName);
110         }
111 
112         return table;
113     }
114 
115     /***
116      * @see uba.db.Database#containsTableNamed(java.lang.String)
117      */
118     public boolean containsTableNamed(String tableName) {
119         return basicTableNamed(tableName) != null;
120     }
121 
122     /***
123      * Las sub-clases deben implementar este método creando la instancia
124      * concreta de la tabla a utilizar.
125      * 
126      * @param tableSchema
127      *            esquema de la tabla a crear.
128      * 
129      * @return una instancia concreta de {@link Table} que depende de la
130      *         implementación.
131      * 
132      * @throws TableCreationException
133      *             si no se pudo crear la tabla.
134      */
135     protected abstract Table basicCreateTable(TableSchema tableSchema)
136             throws TableCreationException;
137 
138     /***
139      * @see uba.db.Database#createTable(uba.db.table.TableSchema)
140      */
141     public Table createTable(TableSchema tableSchema) throws TableAlreadyExistsException,
142             TableCreationException {
143         if (containsTableNamed(tableSchema.tableName())) {
144             throw new TableAlreadyExistsException(this, tableSchema);
145         }
146 
147         Table newTable = basicCreateTable(tableSchema);
148         registerInSystemTables((Integer) idGenerator().nextId(), newTable);
149 
150         return newTable;
151     }
152 
153     /***
154      * Las sub-clases deben implementar este método retornando un objeto que se
155      * encarga de crear los ids para las nuevas tablas.
156      */
157     protected abstract IdGenerator idGenerator();
158 
159     private void registerInSystemTables(Integer tableId, Table table) {
160         addToUserTablesMap(table);
161         addToTablesTable(tableId, table);
162         addToColumnsTable(tableId, table);
163     }
164 
165     /***
166      * @see uba.db.Database#tables()
167      */
168     public Collection tables() {
169         List tables = new ArrayList(systemTables());
170         tables.addAll(userTables());
171         return tables;
172     }
173 
174     private void initializeDataTypeIdMap() {
175         dataTypeIdMap = new HashMap();
176         TableReader reader = dataTypesTable.reader();
177         while (reader.hasMoreRows()) {
178             Row row = reader.fetchRow();
179             dataTypeIdMap.put(row.valueAt(1), row.valueAt(0));
180         }
181         reader.close();
182     }
183 
184     private void initializeSystemTablesMap() {
185         systemTables = new HashMap();
186         systemTables.put(tablesTable.name(), tablesTable);
187         systemTables.put(columnsTable.name(), columnsTable);
188         systemTables.put(dataTypesTable.name(), dataTypesTable);
189     }
190 
191     /***
192      * Crea la instancia concreta de la tabla utilizada para guardar las columnas de
193      * cada tabla del usuario. Por default utilizar un {@link MemoryTable} como 
194      * implementación.
195      * 
196      * @see SystemTableSchemas#COLUMNS_SCHEMA
197      */
198     protected Table createColumnsTable() {
199         return new MemoryTable(SystemTableSchemas.COLUMNS_SCHEMA);
200     }
201 
202     /***
203      * Crea la instancia concreta de la tabla utilizada para guardar las tablas del
204      * usuario. Por default utilizar un {@link MemoryTable} como implementación.
205      * 
206      * @see SystemTableSchemas#COLUMNS_SCHEMA
207      */
208     protected Table createTablesTable() throws Exception {
209         return new MemoryTable(SystemTableSchemas.TABLES_SCHEMA);
210     }
211 
212     private Table createDataTypesTable() {
213         Table dataTypes = new MemoryTable(SystemTableSchemas.DATATYPES_SCHEMA);
214         insertIntoSystemTable(dataTypes,
215                               new Integer(1),
216                               IntegerColumnSpecification.DATATYPE_DISPLAY_STRING);
217         insertIntoSystemTable(dataTypes,
218                               new Integer(2),
219                               CharColumnSpecification.DATATYPE_DISPLAY_STRING);
220 
221         return dataTypes;
222     }
223 
224     private void insertIntoSystemTable(Table table, Object col1, Object col2) {
225         insertIntoSystemTable(table, new Object[] { col1, col2 });
226     }
227 
228     private void insertIntoSystemTable(Table table, Object[] objects) {
229         try {
230             table.insert(objects);
231         } catch (InsertException e) {
232             throw new Error(e);
233         }
234     }
235 
236     /***
237      * Agrega una tabla al diccionario de tablas de usuario.
238      *
239      * @param table la tabla a agregar.
240      */
241     protected void addToUserTablesMap(Table table) {
242         userTables.put(table.name(), table);
243     }
244 
245     /***
246      * Agrega todas las columnas de una tabla, a la tabla {@link #columnsTable()} del 
247      * catalogo.
248      *
249      * @param tableId identificador de la tabla.
250      * @param table la tabla.
251      */
252     protected void addToColumnsTable(Integer tableId, Table table) {
253         Iterator iter = table.columns().iterator();
254         int columnId = 0;
255         while (iter.hasNext()) {
256             columnId++;
257             Column column = (Column) iter.next();
258             insertIntoSystemTable(columnsTable, tableId, new Integer(columnId), column
259                     .name(), dataTypeIdMap.get(column.dataTypeDisplayString()));
260         }
261     }
262 
263     private void insertIntoSystemTable(Table table, Object col1, Object col2,
264             Object col3, Object col4) {
265         insertIntoSystemTable(table, new Object[] { col1, col2, col3, col4 });
266     }
267 
268     /***
269      * Agrega el id y nombre de la tabla a la tabla {@link #tablesTable()} del 
270      * catalogo.
271      *
272      * @param tableId identificador de la tabla.
273      * @param table la tabla.
274      */
275     protected void addToTablesTable(Integer tableId, Table table) {
276         insertIntoSystemTable(tablesTable, tableId, table.name());
277     }
278 
279     /***
280      * @see uba.db.Database#systemTables()
281      */
282     public Collection systemTables() {
283         return systemTables.values();
284     }
285 
286     /***
287      * @see uba.db.Database#userTables()
288      */
289     public Collection userTables() {
290         return userTables.values();
291     }
292 
293     /***
294      * @see uba.db.DatabaseBehavior#basicTableNamed(java.lang.String)
295      */
296     protected Table basicTableNamed(String tableName) {
297         Table table = (Table) systemTables.get(tableName);
298 
299         if (table == null) {
300             table = (Table) userTables.get(tableName);
301         }
302 
303         return table;
304     }
305 
306     /***
307      * @see uba.db.Database#tablesTable()
308      */
309     public Table tablesTable() {
310         return tablesTable;
311     }
312 
313     /***
314      * @see uba.db.Database#dataTypesTable()
315      */
316     public Table dataTypesTable() {
317         return dataTypesTable;
318     }
319 
320     /***
321      * @see uba.db.Database#columnsTable()
322      */
323     public Table columnsTable() {
324         return columnsTable;
325     }
326 }